/**
 * 
 */
package com.arx.interactive;

import com.arx.item.Inventory;
import com.arx.spell.Spell;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.dalonedrau.util.GlobalConstants;

/**
 * @author Donald
 */
public class Interactive extends InteractiveIORetrievalBase {
	/** the singleton instance. */
	private static Interactive	instance;
	/**
	 * Gets the one and only instance of {@link Interactive}.
	 * @return {@link Interactive}
	 */
	public static Interactive getInstance() {
		if (Interactive.instance == null) {
			Interactive.instance = new Interactive();
		}
		return Interactive.instance;
	}
	/** Hidden constructor. */
	private Interactive() {}
	public float ARX_INTERACTIVE_fGetPrice(final InteractiveObject io,
			final InteractiveObject shop) {
		float price = 0;
		if (io != null && io.hasIoFlag(InteractiveGlobals.IO_ITEM)) {

			float durability_ratio = io.getDurability() / io.getMaxDurability();
			float shop_multiply = 1.f;

			if (shop != null) {
				shop_multiply = shop.getShopMultiplier();
			}
			if (io.hasItemData()) {
				price = io.getItemData().getPrice() * shop_multiply
						* durability_ratio;
			}

		}
		return price;
	}
	public long ARX_INTERACTIVE_GetPrice(final InteractiveObject io,
			final InteractiveObject shop) {
		return (long) ARX_INTERACTIVE_fGetPrice(io, shop);
	}
	public long getGoreMode() {
		return goreMode;
	}
	/**
	 * Initializes Interactive Objects Main Structure (pointer list).
	 * @param nb the number of items in the list
	 */
	private void InitInter(final int nb) {
		int val = nb;
		if (val < 10) {
			val = 10;
		}

		nbmax = val;

		if (init) {
			// if already initialized, clear the iobj array
			for (int i = 0; i < iobj.length; i++) {
				iobj[i] = null;
			}
		}

		init = true;
		if (iobj != null && iobj.length != nbmax) {
			iobj = new InteractiveObject[nbmax];
		}
	}
	/**
	 * Determines if the {@link InteractiveObject} is actually the player.
	 * @param io the {@link InteractiveObject}
	 * @return true if the {@link InteractiveObject} is the player; false
	 *         otherwise
	 */
	public boolean isPlayer(final InteractiveObject io) {
		boolean is = false;
		if (io != null) {
			is = io.equals(iobj[0]);
		}
		return is;
	}
	public void ReleaseInter(final InteractiveObject io) {
		if (io != null) {
			if (!FAST_RELEASE) {
				TREATZONE_RemoveIO(io);


		if (io.hasIoFlag(InteractiveGlobals.IO_BODY_CHUNK)) {
			TOTAL_BODY_CHUNKS_COUNT--;

			if (TOTAL_BODY_CHUNKS_COUNT < 0) {
				TOTAL_BODY_CHUNKS_COUNT = 0;
			}
		}
		/*
		if (io.getIgnit_light() > -1) {
			DynLight[io->ignit_light].exist = 0;
			io->ignit_light = -1;
		}

		if (io->ignit_sound != ARX_SOUND_INVALID_RESOURCE)
		{
			ARX_SOUND_Stop(io->ignit_sound);
			io->ignit_sound = ARX_SOUND_INVALID_RESOURCE;
		}

		if (io == FlyingOverIO)
			FlyingOverIO = NULL;

		if ((MasterCamera.exist & 1) && (MasterCamera.io == io))
			MasterCamera.exist = 0;

		if ((MasterCamera.exist & 2) && (MasterCamera.want_io == io))
			MasterCamera.exist = 0;
		
		InterTreeViewItemRemove(io);
		ARX_INTERACTIVE_DestroyDynamicInfo(io);
		IO_UnlinkAllLinkedObjects(io);
		

		// Releases "ToBeDrawn" Transparent Polys linked to this object !
		ARX_INTERACTIVE_MEMO_TWEAK_CLEAR(io);
		ARX_SCRIPT_Timer_Clear_For_IO(io);

		if ((io->obj) && (!(io.hasIoFlag(InteractiveGlobals.IO_CAMERA)) && (!(io.hasIoFlag(InteractiveGlobals.IO_MARKER)) && (!(io.hasIoFlag(InteractiveGlobals.IO_GOLD)))
		{
			ReleaseEERIE3DObj(io->obj);
			io->obj = NULL;
		}
		*/
		Spell.getInstance().ARX_SPELLS_RemoveAllSpellsOn(io);
		/*
		if (io->tweakerinfo != NULL)
		{
			free(io->tweakerinfo);
			io->tweakerinfo = NULL;
		}

		if (io->tweaky)
		{
			ReleaseEERIE3DObj(io->tweaky);
			io->tweaky = NULL;
		}
		*/
		for (long iNbBag = 0; iNbBag < 3; iNbBag++) {
			for (long j = 0; j < InteractiveGlobals.INVENTORY_Y; j++) {
				for (long i = 0; i < InteractiveGlobals.INVENTORY_X; i++) {
					if (inventory[iNbBag][i][j].io == io) {
						inventory[iNbBag][i][j].io = NULL;
					}
				}
			}
		}

		ReleaseScript(&io->script);
		ReleaseScript(&io->over_script);

		for (long n = 0; n < MAX_ANIMS; n++)
		{
			if (io->anims[n] != NULL)
			{
				EERIE_ANIMMANAGER_ReleaseHandle(io->anims[n]);
				io->anims[n] = NULL;
			}
		}

		if (io->shop_category) {
			free(io->shop_category);
		}

		if (io->inventory_skin) {
			free(io->inventory_skin);
		}

		if (io->damagedata >= 0) {
			damages[io->damagedata].exist = 0;
		}

		ARX_IOGROUP_Release(io);
		/*
		if (io->usemesh)
			free(io->usemesh);

		if (ValidDynLight(io->dynlight))
			DynLight[io->dynlight].exist = 0;

		io->dynlight = -1;

		if (ValidDynLight(io->halo.dynlight))
			DynLight[io->halo.dynlight].exist = 0;

		io->halo.dynlight = -1;

		if (io->lastanimvertex)
			free(io->lastanimvertex);

		if (io->usepath)
			free(io->usepath);

		if (io->symboldraw != NULL)
		{
			free(io->symboldraw);
			io->symboldraw = NULL;
		}
		*/
		if (io.hasIoFlag(InteractiveGlobals.IO_NPC)) {
			if (io->_npcdata->ex_rotate != NULL) {
				free(io->_npcdata->ex_rotate);
			}

			if (io->_npcdata->pathfind.list) {
				free(io->_npcdata->pathfind.list);
			}

			free(io->_npcdata);
		}

		if (io.hasIoFlag(InteractiveGlobals.IO_ITEM) 
				&& io.hasItemData()) {
			io.getItemData().freeMemory();
		}
		/*
		if (io.hasIoFlag(InteractiveGlobals.IO_FIX)) {
			free(io->_fixdata);
		}

		if (io.hasIoFlag(InteractiveGlobals.IO_ITEM)) {
			free(io->_itemdata);
		}

		if (io.hasIoFlag(InteractiveGlobals.IO_CAMERA)) {
			if (io->_camdata)
			{
				void * ptr = (void *)ACTIVECAM;

				if (ptr == io->_camdata)
					ACTIVECAM = &subj;

				free(io->_camdata);
			}

			io->_camdata = NULL;
		}

		if ((TSecondaryInventory) && (TSecondaryInventory->io == io))
		{
			TSecondaryInventory = NULL;
		}

		if (io->inventory != NULL) free(io->inventory);

		if (io->weaponmaterial)
			free(io->weaponmaterial);

		if (io->strikespeech)
			free(io->strikespeech);

		if (io->stepmaterial)
			free(io->stepmaterial);

		if (io->armormaterial)
			free(io->armormaterial);

		long ion = GetInterNum(io);

		if (ion > -1) {
			inter.iobj[ion] = NULL;
		}

		free(io);//
		io = null;
		*/
			}
	}
	public void setGoreMode(final long val) {
		goreMode = val;
	}
	public void setInteractiveObject(final InteractiveObject io,
			final int ref) {
		if (iobj == null) {
			iobj = new InteractiveObject[nbmax];
		}
		iobj[ref] = io;
	}
	/**
	 * Sets the nbmax
	 * @param nbmax the nbmax to set
	 */
	public void setNbmax(final int val) {
		nbmax = val;
	}
	private void TREATZONE_RemoveIO(final InteractiveObject io) {
		if (treatio != null) {
			for (int i = 0; i < TREATZONE_CUR; i++) {
				if (treatio[i].getIo() != null
						&& treatio[i].getIo().equals(io)) {
					treatio[i].setIo(null);
					treatio[i].clearIOFlags();
					treatio[i].setShow(0);
				}
			}
		}
	}
	public void UpdateIOInvisibility(final InteractiveObject io) {
		if (io != null && io.getInvisibility() <= 1.0f) {
			if (io.hasGameFlag(InteractiveGlobals.GFLAG_INVISIBILITY)
					&& io.getInvisibility() < 1.f) {
				io.adjustInvisibility(_framedelay * GlobalConstants.DIV1000);

				if (io.getInvisibility() > 1.f) {
					io.setInvisibility(1.f);
				}
			} else if (io
					.hasGameFlag(InteractiveGlobals.GFLAG_INVISIBILITY)
					&& io.getInvisibility() != 0.f) {
				io.adjustInvisibility(-(_framedelay * GlobalConstants.DIV1000));

				if (io.getInvisibility() < 0.f) {
					io.setInvisibility(0.f);
				}
			}
		}
	}
	public boolean ValidIOAddress(final InteractiveObject io) {
		boolean val = false;
		if (io != null) {
			for (int i = 0; i < nbmax; i++) {
				if (iobj[i].equals(io)) {
					val = true;
				}
			}
		}
		return val;
	}
	/**
	 * Determines if a number points to a valid registered interactive item.
	 * @param num the number
	 * @return true if the number points to a registered interactive item; false
	 *         otherwise
	 */
	public boolean validIONum(final int num) {
		boolean valid = false;
		if (num >= 0 && num < nbmax && iobj[num] != null) {
			valid = true;
		}
		return valid;
	}
}
